﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using System.Drawing;
using System.IO;

namespace DX
{
    public class Terrain
    {
        public int WIDTH;
        public int HEIGHT;
        private int MinimumHeight = 1;
        private int MaximumHeight = 70;
        private int[,] heightData;

        public Terrain(int w, int h)
        {
            this.WIDTH = w;
            this.HEIGHT = h;
            if (!LoadHeightDataFromFile("../../images/heightdata.raw"))
            {
                throw new Exception("Failed to load height data from file!");
            }
        }

        public Terrain(string filename)
        {
            if (!LoadHeightDataFromFile(filename))
            {
                throw new Exception(string.Format("Failed to load height data from file: {0}!",filename));
            }
        }

        private bool LoadHeightData_Raw(string filename)
        {
            bool success = true;
            heightData = new int[WIDTH, HEIGHT];
            try
            {
                FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);
                for (int i = 0; i < HEIGHT; i++)
                {
                    for (int y = 0; y < WIDTH; y++)
                    {
                        int height = (int)(br.ReadByte() / 50);
                        heightData[WIDTH - 1 - y, HEIGHT - 1 - i] = height;
                    }
                }
                br.Close();
            }
            catch (Exception eX)
            {
                WinForm.Log(string.Format("Error: Failed loading height data for type RAW with message:{0}", eX.Message));
                success = false;
            }
            return success;
        }

        private bool LoadHeightData_Bmp(string filename)
        {
            bool success = true;
            int offset;
            byte dummy;

            try
            {
                FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                BinaryReader r = new BinaryReader(fs);

                for (int i = 0; i < 10; i++)
                {
                    dummy = r.ReadByte();
                }

                offset = r.ReadByte();
                offset += r.ReadByte() * 256;
                offset += r.ReadByte() * 256 * 256;
                offset += r.ReadByte() * 256 * 256 * 256;

                for (int i = 0; i < 4; i++)
                {
                    dummy = r.ReadByte();
                }

                WIDTH = r.ReadByte();
                WIDTH += r.ReadByte() * 256;
                WIDTH += r.ReadByte() * 256 * 256;
                WIDTH += r.ReadByte() * 256 * 256 * 256;

                HEIGHT = r.ReadByte();
                HEIGHT += r.ReadByte() * 256;
                HEIGHT += r.ReadByte() * 256 * 256;
                HEIGHT += r.ReadByte() * 256 * 256 * 256;

                heightData = new int[WIDTH, HEIGHT];
                for (int i = 0; i < (offset - 26); i++)
                {
                    dummy = r.ReadByte();
                }

                for (int i = 0; i < HEIGHT; i++)
                {
                    for (int y = 0; y < WIDTH; y++)
                    {
                        int height = (int)(r.ReadByte());
                        height += (int)(r.ReadByte());
                        height += (int)(r.ReadByte());
                        height /= 8;
                        heightData[WIDTH - 1 - y, HEIGHT - 1 - i] = height;
                    }
                }
            }
            catch (Exception eX)
            {
                WinForm.Log(string.Format("Error: Failed loading height data for type RAW with message:{0}", eX.Message));
                success = false;
            }
            return success;
        }

        private bool LoadHeightDataFromFile(string filename)
        {
            bool success = false;
            if (File.Exists(filename))
            {
                switch (Path.GetExtension(filename).ToUpper())
                {
                    case ".RAW":
                        success = LoadHeightData_Raw(filename);
                        break;
                    case ".BMP":
                        success = LoadHeightData_Bmp(filename);
                        break;
                    default:
                        WinForm.Log(string.Format("Error: Failed to load height data from file because the file type was unsupported: {0}!", Path.GetExtension(filename).ToUpper()));
                        break;
                }
            }
            else
            {
                WinForm.Log(string.Format("Error: Couldn't load height data from file because the file didn't exist! Filename:{0}", filename));
            }
            return success;
        }

        public CustomVertex.PositionColored[] GetVertices()
        {
            CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[WIDTH * HEIGHT];
            for (int x = 0; x < WIDTH; x++)
            {
                for (int y = 0; y < HEIGHT; y++)
                {
                    vertices[x + y * WIDTH].Position = new Vector3(x, y, heightData[x, y]);
                    vertices[x + y * WIDTH].Color = GetColorForHeight(heightData[x,y]);
                }
            }
            return vertices;
        }

        public int GetColorForHeight(int height)
        {
            if(height < MinimumHeight + (MaximumHeight - MinimumHeight) / 4)
            {
                return Color.Blue.ToArgb();
            }
            else if (height < MinimumHeight + (MaximumHeight - MinimumHeight) * 2 / 4)
            {
                return Color.Green.ToArgb();
            }
            else if (height < MinimumHeight + (MaximumHeight - MinimumHeight) * 3 / 4)
            {
                return Color.Brown.ToArgb();
            }
            else
            {
                return Color.White.ToArgb();
            }
        }



        public short[] GetIndices()
        {
            short[] indices = new short[(WIDTH - 1) * (HEIGHT - 1) * 6];

            for (int x = 0; x < WIDTH - 1; x++)
            {
                for (int y = 0; y < HEIGHT - 1; y++)
                {
                    indices[(x + y * (WIDTH - 1)) * 6] = (short)((x + 1) + (y + 1) * WIDTH);
                    indices[(x + y * (WIDTH - 1)) * 6 + 1] = (short)(x + y * WIDTH);
                    indices[(x + y * (WIDTH - 1)) * 6 + 2] = (short)((x + 1) + y * WIDTH);

                    indices[(x + y * (WIDTH - 1)) * 6 + 3] = (short)((x + 1) + (y + 1) * WIDTH);
                    indices[(x + y * (WIDTH - 1)) * 6 + 4] = (short)(x + (y + 1) * WIDTH);
                    indices[(x + y * (WIDTH - 1)) * 6 + 5] = (short)(x + y * WIDTH);
                }
            }
            return indices;
        }
    }
}
